home *** CD-ROM | disk | FTP | other *** search
- ;; (c) Copyright Taiichi Yuasa and Masami Hagiya, 1984. All rights reserved.
- ;; Copying of this file is authorized to users who have executed the true and
- ;; proper "License Agreement for Kyoto Common LISP" with SIGLISP.
-
- ;;;; seqlib.lsp
- ;;;;
- ;;;; sequence routines
-
-
- (in-package 'lisp)
-
-
- (export '(reduce fill replace
- remove remove-if remove-if-not
- delete delete-if delete-if-not
- count count-if count-if-not
- substitute substitute-if substitute-if-not
- nsubstitute nsubstitute-if nsubstitute-if-not
- find find-if find-if-not
- position position-if position-if-not
- remove-duplicates delete-duplicates
- mismatch search
- sort stable-sort merge))
-
-
- (in-package 'system)
-
-
- (proclaim '(optimize (safety 2) (space 3)))
-
-
- (proclaim '(function seqtype (t) t))
- (defun seqtype (sequence)
- (cond ((listp sequence) 'list)
- ((stringp sequence) 'string)
- ((bit-vector-p sequence) 'bit-vector)
- ((vectorp sequence) (list 'array (array-element-type sequence)))
- (t (error "~S is not a sequence." sequence))))
-
- (proclaim '(function call-test (t t t t) t))
- (defun call-test (test test-not item keyx)
- (cond (test (funcall test item keyx))
- (test-not (not (funcall test-not item keyx)))
- (t (eql item keyx))))
-
- (proclaim '(function check-seq-test (t t) t))
- (defun check-seq-test (test test-not)
- (when (and test test-not)
- (error "Both :TEST and :TEST-NOT were specified.")))
-
- (proclaim '(function check-seq-start-end (t t) t))
- (defun check-seq-start-end (start end)
- (unless (and (si:fixnump start) (si:fixnump end))
- (error "Fixnum expected."))
- (when (> (the fixnum start) (the fixnum end))
- (error "START is greater than END.")))
-
- (proclaim '(function check-seq-args (t t t t) t))
- (defun check-seq-args (test test-not start end)
- (when (and test test-not)
- (error "Both :TEST and :TEST-NOT were specified."))
- (unless (and (si:fixnump start) (si:fixnump end))
- (error "Fixnum expected."))
- (when (> (the fixnum start) (the fixnum end))
- (error "START is greater than END.")))
-
-
- (defun reduce (function sequence
- &key from-end
- (start 0)
- (end (length sequence))
- (initial-value nil ivsp))
- (check-seq-start-end start end)
- (let ((start start) (end end))
- (declare (fixnum start end))
- (cond ((not from-end)
- (when (null ivsp)
- (when (>= start end)
- (return-from reduce (funcall function)))
- (setq initial-value (elt sequence start))
- (incf start))
- (do ((x initial-value
- (funcall function x (prog1 (elt sequence start)
- (incf start)))))
- ((>= start end) x)))
- (t
- (when (null ivsp)
- (when (>= start end)
- (return-from reduce (funcall function)))
- (decf end)
- (setq initial-value (elt sequence end)))
- (do ((x initial-value (funcall function (elt sequence end) x)))
- ((>= start end) x)
- (decf end))))))
-
-
- (defun fill (sequence item
- &key (start 0) (end (length sequence)))
- (check-seq-start-end start end)
- (let ((start start) (end end))
- (declare (fixnum start end))
- (do ((i start (1+ i)))
- ((>= i end) sequence)
- (declare (fixnum i))
- (setf (elt sequence i) item))))
-
-
- (defun replace (sequence1 sequence2
- &key (start1 0) (end1 (length sequence1))
- (start2 0) (end2 (length sequence2)))
- (check-seq-start-end start1 end1)
- (check-seq-start-end start2 end2)
- (let ((start1 start1) (end1 end1) (start2 start2) (end2 end2))
- (declare (fixnum start1 end1 start2 end2))
- (if (and (eq sequence1 sequence2)
- (> start1 start2))
- (do* ((i 0 (1+ i))
- (l (if (< (the fixnum (- end1 start1))
- (the fixnum (- end2 start2)))
- (the fixnum (- end1 start1))
- (the fixnum (- end2 start2))))
- (s1 (+ start1 (the fixnum (1- l))) (1- s1))
- (s2 (+ start2 (the fixnum (1- l))) (1- s2)))
- ((>= i l) sequence1)
- (declare (fixnum i l s1 s2))
- (setf (elt sequence1 s1) (elt sequence2 s2)))
- (do ((i 0 (1+ i))
- (l (if (< (the fixnum (- end1 start1))
- (the fixnum (- end2 start2)))
- (the fixnum (- end1 start1))
- (the fixnum (- end2 start2))))
- (s1 start1 (1+ s1))
- (s2 start2 (1+ s2)))
- ((>= i l) sequence1)
- (declare (fixnum i l s1 s2))
- (setf (elt sequence1 s1) (elt sequence2 s2))))))
-
-
- ;;; DEFSEQ macro.
- ;;; Usage:
- ;;;
- ;;; (DEFSEQ function-name argument-list countp everywherep body)
- ;;;
- ;;; The arguments ITEM and SEQUENCE (PREDICATE and SEQUENCE)
- ;;; and the keyword arguments are automatically supplied.
- ;;; If the function has the :COUNT argument, set COUNTP T.
-
- (eval-when (eval compile)
- (defmacro defseq
- (f args countp everywherep body
- &aux (*macroexpand-hook* 'funcall))
- (setq *body* body)
- (list 'progn
- (let* ((from-end nil)
- (iterate-i '(i start (1+ i)))
- (iterate-i-from-end '(i (1- end) (1- i)))
- (endp-i '(>= i end))
- (endp-i-from-end '(< i start))
- (iterate-i-everywhere '(i 0 (1+ i)))
- (iterate-i-everywhere-from-end '(i (1- l) (1- i)))
- (endp-i-everywhere '(>= i l))
- (endp-i-everywhere-from-end '(< i 0))
- (i-in-range '(and (<= start i) (< i end)))
- (x '(elt sequence i))
- (keyx `(funcall key ,x))
- (satisfies-the-test `(call-test test test-not item ,keyx))
- (number-satisfied
- `(n (internal-count item sequence
- :from-end from-end
- :test test :test-not test-not
- :start start :end end
- ,@(if countp '(:count count))
- :key key)))
- (within-count '(< k count))
- (kount-0 '(k 0))
- (kount-up '(setq k (1+ k))))
- `(defun ,f (,@args item sequence
- &key from-end test test-not
- (start 0) (end (length sequence))
- ,@(if countp '((count (length sequence))))
- (key #'identity)
- ,@(if everywherep
- (list '&aux '(l (length sequence)))
- nil))
- ,@(if countp '((declare (fixnum count))))
- ,@(if everywherep '((declare (fixnum l))))
- (check-seq-args test test-not start end)
- (let ((start start) (end end))
- (declare (fixnum start end))
- (if (not from-end)
- ,(eval-body)
- ,(progn (setq from-end t
- iterate-i iterate-i-from-end
- endp-i endp-i-from-end
- iterate-i-everywhere
- iterate-i-everywhere-from-end
- endp-i-everywhere
- endp-i-everywhere-from-end)
- (eval-body))))))
- `(defun ,(intern (si:string-concatenate (string f) "-IF")
- (symbol-package f))
- (,@args predicate sequence
- &key from-end
- (start 0) (end (length sequence))
- ,@(if countp '((count (length sequence))))
- (key #'identity))
- (,f ,@args predicate sequence
- :from-end from-end
- :test #'funcall
- :start start :end end
- ,@(if countp '(:count count))
- :key key))
- `(defun ,(intern (si:string-concatenate (string f) "-IF-NOT")
- (symbol-package f))
- (,@args predicate sequence
- &key from-end
- (start 0) (end (length sequence))
- ,@(if countp '((count (length sequence))))
- (key #'identity))
- (,f ,@args predicate sequence
- :from-end from-end
- :test-not #'funcall
- :start start :end end
- ,@(if countp '(:count count))
- :key key))
- (list 'quote f)))
-
- (defmacro eval-body () *body*)
- )
-
-
- (defseq remove () t nil
- (if (not from-end)
- `(if (listp sequence)
- (let ((l sequence) (l1 nil))
- (do ((i 0 (1+ i)))
- ((>= i start))
- (declare (fixnum i))
- (push (car l) l1)
- (pop l))
- (do ((i start (1+ i)) (j 0))
- ((or (>= i end) (>= j count) (endp l))
- (nreconc l1 l))
- (declare (fixnum i j))
- (cond ((call-test test test-not item (funcall key (car l)))
- (incf j)
- (pop l))
- (t
- (push (car l) l1)
- (pop l)))))
- (delete item sequence
- :from-end from-end
- :test test :test-not test-not
- :start start :end end
- :count count
- :key key))
- `(delete item sequence
- :from-end from-end
- :test test :test-not test-not
- :start start :end end
- :count count
- :key key)))
-
-
- (defseq delete () t t
- (if (not from-end)
- `(if (listp sequence)
- (let* ((l0 (cons nil sequence)) (l l0))
- (do ((i 0 (1+ i)))
- ((>= i start))
- (declare (fixnum i))
- (pop l))
- (do ((i start (1+ i)) (j 0))
- ((or (>= i end) (>= j count) (endp (cdr l))) (cdr l0))
- (declare (fixnum i j))
- (cond ((call-test test test-not item (funcall key (cadr l)))
- (incf j)
- (rplacd l (cddr l)))
- (t (setq l (cdr l))))))
- (let (,number-satisfied)
- (declare (fixnum n))
- (when (< n count) (setq count n))
- (do ((newseq
- (make-sequence (seqtype sequence)
- (the fixnum (- l count))))
- ,iterate-i-everywhere
- (j start)
- ,kount-0)
- (,endp-i-everywhere newseq)
- (declare (fixnum i j k))
- (cond ((and ,i-in-range ,within-count ,satisfies-the-test)
- ,kount-up)
- (t (setf (elt newseq j) ,x)
- (incf j))))))
- `(let (,number-satisfied)
- (declare (fixnum n))
- (when (< n count) (setq count n))
- (do ((newseq
- (make-sequence (seqtype sequence) (the fixnum (- l count))))
- ,iterate-i-everywhere
- (j (- (the fixnum (1- end)) n))
- ,kount-0)
- (,endp-i-everywhere newseq)
- (declare (fixnum i j k))
- (cond ((and ,i-in-range ,within-count ,satisfies-the-test)
- ,kount-up)
- (t (setf (elt newseq j) ,x)
- (decf j)))))))
-
-
- (defseq count () nil nil
- `(do (,iterate-i ,kount-0)
- (,endp-i k)
- (declare (fixnum i k))
- (when (and ,satisfies-the-test)
- ,kount-up)))
-
-
- (defseq internal-count () t nil
- `(do (,iterate-i ,kount-0)
- (,endp-i k)
- (declare (fixnum i k))
- (when (and ,within-count ,satisfies-the-test)
- ,kount-up)))
-
-
- (defseq substitute (newitem) t t
- `(do ((newseq (make-sequence (seqtype sequence) l))
- ,iterate-i-everywhere
- ,kount-0)
- (,endp-i-everywhere newseq)
- (declare (fixnum i k))
- (cond ((and ,i-in-range ,within-count ,satisfies-the-test)
- (setf (elt newseq i) newitem)
- ,kount-up)
- (t (setf (elt newseq i) ,x))))))
-
-
- (defseq nsubstitute (newitem) t nil
- `(do (,iterate-i ,kount-0)
- (,endp-i sequence)
- (declare (fixnum i k))
- (when (and ,within-count ,satisfies-the-test)
- (setf ,x newitem)
- ,kount-up)))
-
-
- (defseq find () nil nil
- `(do (,iterate-i)
- (,endp-i nil)
- (declare (fixnum i))
- (when ,satisfies-the-test (return ,x))))
-
-
- (defseq position () nil nil
- `(do (,iterate-i)
- (,endp-i nil)
- (declare (fixnum i))
- (when ,satisfies-the-test (return i))))
-
-
- (defun remove-duplicates (sequence
- &key from-end
- test test-not
- (start 0 startsp)
- (end (length sequence) endsp)
- (key #'identity))
- (check-seq-args test test-not start end)
- (when (and (listp sequence) (not from-end) (not startsp) (not endsp))
- (when (endp sequence) (return-from remove-duplicates nil))
- (do ((l sequence (cdr l)) (l1 nil))
- ((endp (cdr l))
- (return-from remove-duplicates (nreconc l1 l)))
- (unless (member1 (car l) (cdr l)
- :test test :test-not test-not
- :key key)
- (setq l1 (cons (car l) l1)))))
- (delete-duplicates sequence
- :from-end from-end
- :test test :test-not test-not
- :start start :end end
- :key key))
-
-
- (defun delete-duplicates (sequence
- &key from-end
- test test-not
- (start 0 startsp)
- (end (length sequence) endsp)
- (key #'identity)
- &aux (l (length sequence)))
- (declare (fixnum l))
- (check-seq-args test test-not start end)
- (when (and (listp sequence) (not from-end) (not startsp) (not endsp))
- (when (endp sequence) (return-from delete-duplicates nil))
- (do ((l sequence))
- ((endp (cdr l))
- (return-from delete-duplicates sequence))
- (cond ((member1 (car l) (cdr l)
- :test test :test-not test-not
- :key key)
- (rplaca l (cadr l))
- (rplacd l (cddr l)))
- (t (setq l (cdr l))))))
- (let ((start start) (end end))
- (declare (fixnum start end))
- (if (not from-end)
- (do ((n 0)
- (i start (1+ i)))
- ((>= i end)
- (do ((newseq (make-sequence (seqtype sequence)
- (the fixnum (- l n))))
- (i 0 (1+ i))
- (j 0))
- ((>= i l) newseq)
- (declare (fixnum i j))
- (cond ((and (<= start i)
- (< i end)
- (position (funcall key (elt sequence i))
- sequence
- :test test
- :test-not test-not
- :start (the fixnum (1+ i))
- :end end
- :key key)))
- (t
- (setf (elt newseq j) (elt sequence i))
- (incf j)))))
- (declare (fixnum n i))
- (when (position (funcall key (elt sequence i))
- sequence
- :test test
- :test-not test-not
- :start (the fixnum (1+ i))
- :end end
- :key key)
- (incf n)))
- (do ((n 0)
- (i (1- end) (1- i)))
- ((< i start)
- (do ((newseq (make-sequence (seqtype sequence)
- (the fixnum (- l n))))
- (i (1- l) (1- i))
- (j (- (the fixnum (1- l)) n)))
- ((< i 0) newseq)
- (declare (fixnum i j))
- (cond ((and (<= start i)
- (< i end)
- (position (funcall key (elt sequence i))
- sequence
- :from-end t
- :test test
- :test-not test-not
- :start start
- :end i
- :key key)))
- (t
- (setf (elt newseq j) (elt sequence i))
- (decf j)))))
- (declare (fixnum n i))
- (when (position (funcall key (elt sequence i))
- sequence
- :from-end t
- :test test
- :test-not test-not
- :start start
- :end i
- :key key)
- (incf n))))))
-
-
- (defun mismatch (sequence1 sequence2
- &key from-end test test-not
- (key #'identity)
- (start1 0)
- (start2 0)
- (end1 (length sequence1))
- (end2 (length sequence2)))
- (check-seq-test test test-not)
- (check-seq-start-end start1 end1)
- (check-seq-start-end start2 end2)
- (let ((start1 start1) (end1 end1) (start2 start2) (end2 end2))
- (declare (fixnum start1 end1 start2 end2))
- (if (not from-end)
- (do ((i1 start1 (1+ i1))
- (i2 start2 (1+ i2)))
- ((or (>= i1 end1) (>= i2 end2))
- (if (and (>= i1 end1) (>= i2 end2)) nil i1))
- (declare (fixnum i1 i2))
- (unless (call-test test test-not
- (funcall key (elt sequence1 i1))
- (funcall key (elt sequence2 i2)))
- (return i1)))
- (do ((i1 (1- end1) (1- i1))
- (i2 (1- end2) (1- i2)))
- ((or (< i1 start1) (< i2 start2))
- (if (and (< i1 start1) (< i2 start2)) nil i1))
- (declare (fixnum i1 i2))
- (unless (call-test test test-not
- (funcall key (elt sequence1 i1))
- (funcall key (elt sequence2 i2)))
- (return i1))))))
-
-
- (defun search (sequence1 sequence2
- &key from-end test test-not
- (key #'identity)
- (start1 0)
- (start2 0)
- (end1 (length sequence1))
- (end2 (length sequence2)))
- (check-seq-test test test-not)
- (check-seq-start-end start1 end1)
- (check-seq-start-end start2 end2)
- (let ((start1 start1) (end1 end1) (start2 start2) (end2 end2))
- (declare (fixnum start1 end1 start2 end2))
- (if (not from-end)
- (loop
- (do ((i1 start1 (1+ i1))
- (i2 start2 (1+ i2)))
- ((>= i1 end1) (return-from search start2))
- (declare (fixnum i1 i2))
- (when (>= i2 end2) (return-from search nil))
- (unless (call-test test test-not
- (funcall key (elt sequence1 i1))
- (funcall key (elt sequence2 i2)))
- (return nil)))
- (incf start2))
- (loop
- (do ((i1 (1- end1) (1- i1))
- (i2 (1- end2) (1- i2)))
- ((< i1 start1) (return-from search (the fixnum (1+ i2))))
- (declare (fixnum i1 i2))
- (when (< i2 start2) (return-from search nil))
- (unless (call-test test test-not
- (funcall key (elt sequence1 i1))
- (funcall key (elt sequence2 i2)))
- (return nil)))
- (decf end2)))))
-
-
- (defun sort (sequence predicate &key (key #'identity))
- (if (listp sequence)
- (list-merge-sort sequence predicate key)
- (quick-sort sequence 0 (the fixnum (length sequence)) predicate key)))
-
-
- (defun list-merge-sort (l predicate key)
- (labels
- ((sort (l)
- (prog ((i 0) left right l0 l1 key-left key-right)
- (declare (fixnum i))
- (setq i (length l))
- (cond ((< i 2) (return l))
- ((= i 2)
- (setq key-left (funcall key (car l)))
- (setq key-right (funcall key (cadr l)))
- (cond ((funcall predicate key-left key-right) (return l))
- ((funcall predicate key-right key-left)
- (return (nreverse l)))
- (t (return l)))))
- (setq i (floor i 2))
- (do ((j 1 (1+ j)) (l1 l (cdr l1)))
- ((>= j i)
- (setq left l)
- (setq right (cdr l1))
- (rplacd l1 nil))
- (declare (fixnum j)))
- (setq left (sort left))
- (setq right (sort right))
- (cond ((endp left) (return right))
- ((endp right) (return left)))
- (setq l0 (cons nil nil))
- (setq l1 l0)
- (setq key-left (funcall key (car left)))
- (setq key-right (funcall key (car right)))
- loop
- (cond ((funcall predicate key-left key-right) (go left))
- ((funcall predicate key-right key-left) (go right))
- (t (go left)))
- left
- (rplacd l1 left)
- (setq l1 (cdr l1))
- (setq left (cdr left))
- (when (endp left)
- (rplacd l1 right)
- (return (cdr l0)))
- (setq key-left (funcall key (car left)))
- (go loop)
- right
- (rplacd l1 right)
- (setq l1 (cdr l1))
- (setq right (cdr right))
- (when (endp right)
- (rplacd l1 left)
- (return (cdr l0)))
- (setq key-right (funcall key (car right)))
- (go loop))))
- (sort l)))
-
-
- #|
- (defun list-quick-sort (l predicate key)
- (if (or (endp l) (endp (cdr l)))
- l
- (multiple-value-bind (x y)
- (list-quick-sort-partition (car l) (cdr l) predicate key)
- (nconc (list-quick-sort x predicate key)
- (list (car l))
- (list-quick-sort y predicate key)))))
-
- (defun list-quick-sort-partition (k l predicate key)
- (do ((l l (cdr l)) (x nil) (y nil))
- ((endp l) (values (nreverse x) (nreverse y)))
- (if (funcall predicate (funcall key (car l)) (funcall key k))
- (setq x (cons (car l) x))
- (setq y (cons (car l) y)))))
- |#
-
-
- (proclaim '(function quick-sort (t fixnum fixnum t t)))
-
- (defun quick-sort (sequence start end predicate key &aux (j 0) (k 0))
- (declare (fixnum start end j k))
- (when (<= end (the fixnum (1+ start)))
- (return-from quick-sort sequence))
- (setq j start)
- (setq k (1- end))
- (do ((d (elt sequence start)))
- ((> j k))
- (do ()
- ((or (> j k)
- (funcall predicate
- (funcall key (elt sequence k))
- (funcall key d))))
- (decf k))
- (when (< k start)
- (quick-sort sequence (1+ start) end predicate key)
- (return-from quick-sort sequence))
- (do ()
- ((or (> j k)
- (not (funcall predicate
- (funcall key (elt sequence j))
- (funcall key d)))))
- (incf j))
- (when (> j k) (return))
- (psetf (elt sequence j) (elt sequence k)
- (elt sequence k) (elt sequence j))
- (incf j)
- (decf k))
- (quick-sort sequence start j predicate key)
- (quick-sort sequence j end predicate key)
- sequence)
-
-
- (defun stable-sort (sequence predicate &key (key #'identity))
- (if (listp sequence)
- (list-merge-sort sequence predicate key)
- (if (or (stringp sequence) (bit-vector-p sequence))
- (sort sequence predicate :key key)
- (coerce (list-merge-sort (coerce sequence 'list)
- predicate
- key)
- (seqtype sequence)))))
-
-
- (defun merge (result-type sequence1 sequence2 predicate
- &key (key #'identity)
- &aux (l1 (length sequence1)) (l2 (length sequence2)))
- (declare (fixnum l1 l2))
- (do ((newseq (make-sequence result-type (the fixnum (+ l1 l2))))
- (j 0 (1+ j))
- (i1 0)
- (i2 0))
- ((and (= i1 l1) (= i2 l2)) newseq)
- (declare (fixnum j i1 i2))
- (cond ((and (< i1 l1) (< i2 l2))
- (cond ((funcall predicate
- (funcall key (elt sequence1 i1))
- (funcall key (elt sequence2 i2)))
- (setf (elt newseq j) (elt sequence1 i1))
- (incf i1))
- ((funcall predicate
- (funcall key (elt sequence2 i2))
- (funcall key (elt sequence1 i1)))
- (setf (elt newseq j) (elt sequence2 i2))
- (incf i2))
- (t
- (setf (elt newseq j) (elt sequence1 i1))
- (incf i1))))
- ((< i1 l1)
- (setf (elt newseq j) (elt sequence1 i1))
- (incf i1))
- (t
- (setf (elt newseq j) (elt sequence2 i2))
- (incf i2)))))
-